package com.recharge.config;


import com.recharge.common.util.RedisUtil;
import com.recharge.domain.context.MyRedisSessionDao;
import com.recharge.domain.context.SelfSessionDao;
import com.recharge.filters.*;

import com.recharge.service.impl.ShiroServiceImpl;
import com.recharge.shiro.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;

import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;

import org.crazycake.shiro.RedisCacheManager;

import org.crazycake.shiro.RedisSentinelManager;
import org.crazycake.shiro.RedisSessionDAO;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisSentinelPool;

@Configuration
public class ShiroConfig {

    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    private final String CACHE_KEY = "shiro:cache:";

    private final String SESSION_KEY = "shiro:session:";

    @Value("${spring.redis.sentinel.nodes}")
    private String nodes;
    @Value("${spring.redis.sentinel.master}")
    private String master;


    @Autowired
    RedisUtil redisUtil;
    @Autowired
    JedisSentinelPool jedisSentinelPool;

    @Autowired
    MyRedisSessionDao myRedisSessionDao;

    @Autowired
    private SelfSessionDao selfSessionDao;

    /**
     * 开启Shiro-aop注解支持：使用代理方式所以需要开启代码支持
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * Shiro基础配置
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager, ShiroServiceImpl shiroConfig){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 自定义过滤器
        Map<String, Filter> filtersMap = new LinkedHashMap<>();
        filtersMap.put( "token", new TokenCheckFilter(redisUtil) );
        filtersMap.put( "zqRoles", new MyRolesAuthorizationFilter() );
        filtersMap.put( "permission", new PermissionsAuthorizationFilter() );
        shiroFilterFactoryBean.setFilters(filtersMap);
        // 登录的路径: 如果你没有登录则会跳到这个页面中 - 如果没有设置值则会默认跳转到工程根目录下的"/login.jsp"页面 或 "/login" 映射
//        shiroFilterFactoryBean.setLoginUrl("/api/auth/unLogin");
        // 登录成功后跳转的主页面 （这里没用，前端vue控制了跳转）
//        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 设置没有权限时跳转的url
//        shiroFilterFactoryBean.setUnauthorizedUrl("/api/auth/unauth");

        shiroFilterFactoryBean.setFilterChainDefinitionMap( shiroConfig.loadFilterChainDefinitionMap() );
        return shiroFilterFactoryBean;
    }


    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
        defaultSecurityManager.setSessionManager(sessionManager());
        defaultSecurityManager.setCacheManager(cacheManager());
        defaultSecurityManager.setRealm(customRealm());
        return defaultSecurityManager;
    }

    @Bean
    public CustomRealm customRealm() {
        CustomRealm customRealm = new CustomRealm();
        customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return customRealm;
    }

    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        // 散列的次数，比如散列两次，相当于 md5(md5(""));
        hashedCredentialsMatcher.setHashIterations(1024);
        return hashedCredentialsMatcher;
    }


    /**
     * redisManager
     *
     * @return
     *//*
    public RedisManager redisManager() {
        logger.debug("redis Manager");
        RedisManager redisManager = new RedisManager();
        redisManager.setJedisPoolConfig();
        return redisManager;
    }*/

    @ConfigurationProperties("spring.redis.sentinel")
    @Bean
    public RedisSentinelManager redisSentinelManager() {
        RedisSentinelManager redisSentinelManager = new RedisSentinelManager();
        redisSentinelManager.setHost(nodes);
        redisSentinelManager.setMasterName(master);
        return redisSentinelManager;
    }

    /**
     * cacheManager
     *
     * @return
     */
    public RedisCacheManager cacheManager() {
        logger.debug("cache Manager");
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisSentinelManager());
        redisCacheManager.setKeyPrefix(CACHE_KEY);
        // 配置缓存的话要求放在session里面的实体类必须有个id标识 注：这里id为用户表中的主键，否-> 报：User must has getter for field: xx
        redisCacheManager.setPrincipalIdFieldName("username");
        redisCacheManager.setExpire(-2);
        return redisCacheManager;
    }

    /**
     * SessionID生成器
     */
    @Bean
    public ShiroSessionIdGenerator sessionIdGenerator(){
        return new ShiroSessionIdGenerator();
    }

    /**
     * redisSessionDAO
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        logger.debug("redis session");
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisSentinelManager());
        redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());
        redisSessionDAO.setKeyPrefix(SESSION_KEY);
//        redisSessionDAO.setExpire(-1);
        return redisSessionDAO;
    }



   /**
    * sessionManager
  */
    @Bean
    public ShiroSession sessionManager() {
        logger.debug("session manager");
        //将我们继承后重写的shiro session 注册
        ShiroSession shiroSession = new ShiroSession();
        // 自定义sessionDAO
        shiroSession.setSessionDAO(redisSessionDAO());
        // 自定义id生成器
//        selfSessionDao.setSessionIdGenerator(sessionIdGenerator());
        return shiroSession;
    }
}
